]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
data: Move cldr2json fork into subdirectory
authorFlorian Müllner <fmuellner@gnome.org>
Fri, 27 Mar 2020 15:35:00 +0000 (16:35 +0100)
committerFlorian Müllner <florian.muellner@gmail.com>
Fri, 27 Mar 2020 16:44:27 +0000 (16:44 +0000)
The module was imported into the toplevel in !424, but that's at
least a bit weird:
 - it's a helper script for one particular aspect (OSK layouts)
 - it adds a README.mdwn to our own README.md, and a test/ directory
   to our tests/

Move the whole thing to a subdirectory under data/, which is more
appropriate.

https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1136

12 files changed:
README.mdwn [deleted file]
cldr2json.py [deleted file]
data/cldr2json/README.md [new file with mode: 0644]
data/cldr2json/cldr2json.py [new file with mode: 0755]
data/cldr2json/test/__init__.py [new file with mode: 0644]
data/cldr2json/test/data/fr-t-k0-android.xml [new file with mode: 0644]
data/cldr2json/test/data/fr.json [new file with mode: 0644]
data/cldr2json/test/test_cldr2json.py [new file with mode: 0755]
test/__init__.py [deleted file]
test/data/fr-t-k0-android.xml [deleted file]
test/data/fr.json [deleted file]
test/test_cldr2json.py [deleted file]

diff --git a/README.mdwn b/README.mdwn
deleted file mode 100644 (file)
index 0eb54bc..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-cldr2json
-=========
-
-This script converts Unicode CLDR android keyboard layouts to JSON usable by
-GNOME Shell.
-
-CLDR keyboard layouts can be found at
-<http://www.unicode.org/Public/cldr/latest/keyboards.zip>
-
-
-Usage
-=====
-
-    ./cldr2json <input file or directory> <output directory>
-
-example:
-
-    ./cldr2json cldr/keyboards/android/ json_layouts/
-
-
-Keyboard layout mapping
-=======================
-
-Unicode CLDR layout identifiers are language codes, while XKB layout
-identifiers are... something else. The mapping between the two currently uses
-heuristic based on the layout descriptions, in this order:
-
-- if the CLDR layout description matches an XKB layout description, chose its
-  XKB identifier
-- if one word of the CLDR layout description matches an XKB layout
-  description, chose its XKB identifier
-- if the CLDR layout description matches one word of an XKB layout description,
-  chose its XKB identifier
-
-That doesn't always work. For instance it fails for "en" language, that should
-match "us" XKB identifier. For such cases, there is a mapping in
-LOCALE_TO_XKB_OVERRIDES at the top of the script. If you discover a weird
-mapping of if you get a "failed to find XKB mapping for <locale>" warning then
-please consider adding an override there.
-
diff --git a/cldr2json.py b/cldr2json.py
deleted file mode 100755 (executable)
index 360030b..0000000
+++ /dev/null
@@ -1,208 +0,0 @@
-#!/usr/bin/python3
-#
-# Copyright 2015  Daiki Ueno <dueno@src.gnome.org>
-#           2016  Parag Nemade <pnemade@redhat.com>
-#           2017  Alan <alan@boum.org>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as
-# published by the Free Software Foundation; either version 2 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, see
-# <http://www.gnu.org/licenses/>.
-
-import glob
-import json
-import locale
-import logging
-import os
-import re
-import sys
-import xml.etree.ElementTree
-
-import gi
-gi.require_version('GnomeDesktop', '3.0')   # NOQA: E402
-from gi.repository import GnomeDesktop
-
-ESCAPE_PATTERN = re.compile(r'\\u\{([0-9A-Fa-f]+?)\}')
-ISO_PATTERN = re.compile(r'[A-E]([0-9]+)')
-
-LOCALE_TO_XKB_OVERRIDES = {
-    'af':    'za',
-    'en':    'us',
-    'en-GB': 'uk',
-    'es-US': 'latam',
-    'fr-CA': 'ca',
-    'hi':    'in+bolnagri',
-    'ky':    'kg',
-    'nl-BE': 'be',
-    'zu':    None
-}
-
-
-def parse_single_key(value):
-    def unescape(m):
-        return chr(int(m.group(1), 16))
-    value = ESCAPE_PATTERN.sub(unescape, value)
-    return value
-
-
-def parse_rows(keymap):
-    unsorted_rows = {}
-    for _map in keymap.iter('map'):
-        value = _map.get('to')
-        key = [parse_single_key(value)]
-        iso = _map.get('iso')
-        if not ISO_PATTERN.match(iso):
-            sys.stderr.write('invalid ISO key name: %s\n' % iso)
-            continue
-        if not iso[0] in unsorted_rows:
-            unsorted_rows[iso[0]] = []
-        unsorted_rows[iso[0]].append((int(iso[1:]), key))
-        # add subkeys
-        longPress = _map.get('longPress')
-        if longPress:
-            for value in longPress.split(' '):
-                subkey = parse_single_key(value)
-                key.append(subkey)
-
-    rows = []
-    for k, v in sorted(list(unsorted_rows.items()),
-                       key=lambda x: x[0],
-                       reverse=True):
-        row = []
-        for key in sorted(v, key=lambda x: x):
-            row.append(key[1])
-        rows.append(row)
-
-    return rows
-
-
-def convert_xml(tree):
-    root = {}
-    for xml_keyboard in tree.iter("keyboard"):
-        locale_full = xml_keyboard.get("locale")
-        locale, sep, end = locale_full.partition("-t-")
-    root["locale"] = locale
-    for xml_name in tree.iter("name"):
-        name = xml_name.get("value")
-    root["name"] = name
-    root["levels"] = []
-    # parse levels
-    for index, keymap in enumerate(tree.iter('keyMap')):
-        # FIXME: heuristics here
-        modifiers = keymap.get('modifiers')
-        if not modifiers:
-            mode = 'default'
-            modifiers = ''
-        elif 'shift' in modifiers.split(' '):
-            mode = 'latched'
-            modifiers = 'shift'
-        else:
-            mode = 'locked'
-        level = {}
-        level["level"] = modifiers
-        level["mode"] = mode
-        level["rows"] = parse_rows(keymap)
-        root["levels"].append(level)
-    return root
-
-
-def locale_to_xkb(locale, name):
-    if locale in sorted(LOCALE_TO_XKB_OVERRIDES.keys()):
-        xkb = LOCALE_TO_XKB_OVERRIDES[locale]
-        logging.debug("override for %s → %s",
-                      locale, xkb)
-        if xkb:
-            return xkb
-        else:
-            raise KeyError("layout %s explicitely disabled in overrides"
-                           % locale)
-    xkb_names = sorted(name_to_xkb.keys())
-    if name in xkb_names:
-        return name_to_xkb[name]
-    else:
-        logging.debug("name %s failed" % name)
-    for sub_name in name.split(' '):
-        if sub_name in xkb_names:
-            xkb = name_to_xkb[sub_name]
-            logging.debug("dumb mapping failed but match with locale word: "
-                          "%s (%s) → %s (%s)",
-                          locale, name, xkb, sub_name)
-            return xkb
-        else:
-            logging.debug("sub_name failed")
-    for xkb_name in xkb_names:
-        for xkb_sub_name in xkb_name.split(' '):
-            if xkb_sub_name.strip('()') == name:
-                xkb = name_to_xkb[xkb_name]
-                logging.debug("dumb mapping failed but match with xkb word: "
-                              "%s (%s) → %s (%s)",
-                              locale, name, xkb, xkb_name)
-                return xkb
-    raise KeyError("failed to find XKB mapping for %s" % locale)
-
-
-def convert_file(source_file, destination_path):
-    logging.info("Parsing %s", source_file)
-
-    itree = xml.etree.ElementTree.ElementTree()
-    itree.parse(source_file)
-
-    root = convert_xml(itree)
-
-    try:
-        xkb_name = locale_to_xkb(root["locale"], root["name"])
-    except KeyError as e:
-        logging.warn(e)
-        return False
-    destination_file = os.path.join(destination_path, xkb_name + ".json")
-
-    with open(destination_file, 'w', encoding="utf-8") as dest_fd:
-        json.dump(root, dest_fd, ensure_ascii=False, indent=2, sort_keys=True)
-
-    logging.debug("written %s", destination_file)
-
-
-def load_xkb_mappings():
-    xkb = GnomeDesktop.XkbInfo()
-    layouts = xkb.get_all_layouts()
-    name_to_xkb = {}
-
-    for layout in layouts:
-        name = xkb.get_layout_info(layout).display_name
-        name_to_xkb[name] = layout
-
-    return name_to_xkb
-
-
-locale.setlocale(locale.LC_ALL, "C")
-name_to_xkb = load_xkb_mappings()
-
-
-if __name__ == "__main__":
-    if "DEBUG" in os.environ:
-        logging.basicConfig(level=logging.DEBUG)
-
-    if len(sys.argv) < 2:
-        print("supply a CLDR keyboard file")
-        sys.exit(1)
-
-    if len(sys.argv) < 3:
-        print("supply an output directory")
-        sys.exit(1)
-
-    source = sys.argv[1]
-    destination = sys.argv[2]
-    if os.path.isfile(source):
-        convert_file(source, destination)
-    elif os.path.isdir(source):
-        for path in glob.glob(source + "/*-t-k0-android.xml"):
-            convert_file(path, destination)
diff --git a/data/cldr2json/README.md b/data/cldr2json/README.md
new file mode 100644 (file)
index 0000000..0eb54bc
--- /dev/null
@@ -0,0 +1,40 @@
+cldr2json
+=========
+
+This script converts Unicode CLDR android keyboard layouts to JSON usable by
+GNOME Shell.
+
+CLDR keyboard layouts can be found at
+<http://www.unicode.org/Public/cldr/latest/keyboards.zip>
+
+
+Usage
+=====
+
+    ./cldr2json <input file or directory> <output directory>
+
+example:
+
+    ./cldr2json cldr/keyboards/android/ json_layouts/
+
+
+Keyboard layout mapping
+=======================
+
+Unicode CLDR layout identifiers are language codes, while XKB layout
+identifiers are... something else. The mapping between the two currently uses
+heuristic based on the layout descriptions, in this order:
+
+- if the CLDR layout description matches an XKB layout description, chose its
+  XKB identifier
+- if one word of the CLDR layout description matches an XKB layout
+  description, chose its XKB identifier
+- if the CLDR layout description matches one word of an XKB layout description,
+  chose its XKB identifier
+
+That doesn't always work. For instance it fails for "en" language, that should
+match "us" XKB identifier. For such cases, there is a mapping in
+LOCALE_TO_XKB_OVERRIDES at the top of the script. If you discover a weird
+mapping of if you get a "failed to find XKB mapping for <locale>" warning then
+please consider adding an override there.
+
diff --git a/data/cldr2json/cldr2json.py b/data/cldr2json/cldr2json.py
new file mode 100755 (executable)
index 0000000..360030b
--- /dev/null
@@ -0,0 +1,208 @@
+#!/usr/bin/python3
+#
+# Copyright 2015  Daiki Ueno <dueno@src.gnome.org>
+#           2016  Parag Nemade <pnemade@redhat.com>
+#           2017  Alan <alan@boum.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this program; if not, see
+# <http://www.gnu.org/licenses/>.
+
+import glob
+import json
+import locale
+import logging
+import os
+import re
+import sys
+import xml.etree.ElementTree
+
+import gi
+gi.require_version('GnomeDesktop', '3.0')   # NOQA: E402
+from gi.repository import GnomeDesktop
+
+ESCAPE_PATTERN = re.compile(r'\\u\{([0-9A-Fa-f]+?)\}')
+ISO_PATTERN = re.compile(r'[A-E]([0-9]+)')
+
+LOCALE_TO_XKB_OVERRIDES = {
+    'af':    'za',
+    'en':    'us',
+    'en-GB': 'uk',
+    'es-US': 'latam',
+    'fr-CA': 'ca',
+    'hi':    'in+bolnagri',
+    'ky':    'kg',
+    'nl-BE': 'be',
+    'zu':    None
+}
+
+
+def parse_single_key(value):
+    def unescape(m):
+        return chr(int(m.group(1), 16))
+    value = ESCAPE_PATTERN.sub(unescape, value)
+    return value
+
+
+def parse_rows(keymap):
+    unsorted_rows = {}
+    for _map in keymap.iter('map'):
+        value = _map.get('to')
+        key = [parse_single_key(value)]
+        iso = _map.get('iso')
+        if not ISO_PATTERN.match(iso):
+            sys.stderr.write('invalid ISO key name: %s\n' % iso)
+            continue
+        if not iso[0] in unsorted_rows:
+            unsorted_rows[iso[0]] = []
+        unsorted_rows[iso[0]].append((int(iso[1:]), key))
+        # add subkeys
+        longPress = _map.get('longPress')
+        if longPress:
+            for value in longPress.split(' '):
+                subkey = parse_single_key(value)
+                key.append(subkey)
+
+    rows = []
+    for k, v in sorted(list(unsorted_rows.items()),
+                       key=lambda x: x[0],
+                       reverse=True):
+        row = []
+        for key in sorted(v, key=lambda x: x):
+            row.append(key[1])
+        rows.append(row)
+
+    return rows
+
+
+def convert_xml(tree):
+    root = {}
+    for xml_keyboard in tree.iter("keyboard"):
+        locale_full = xml_keyboard.get("locale")
+        locale, sep, end = locale_full.partition("-t-")
+    root["locale"] = locale
+    for xml_name in tree.iter("name"):
+        name = xml_name.get("value")
+    root["name"] = name
+    root["levels"] = []
+    # parse levels
+    for index, keymap in enumerate(tree.iter('keyMap')):
+        # FIXME: heuristics here
+        modifiers = keymap.get('modifiers')
+        if not modifiers:
+            mode = 'default'
+            modifiers = ''
+        elif 'shift' in modifiers.split(' '):
+            mode = 'latched'
+            modifiers = 'shift'
+        else:
+            mode = 'locked'
+        level = {}
+        level["level"] = modifiers
+        level["mode"] = mode
+        level["rows"] = parse_rows(keymap)
+        root["levels"].append(level)
+    return root
+
+
+def locale_to_xkb(locale, name):
+    if locale in sorted(LOCALE_TO_XKB_OVERRIDES.keys()):
+        xkb = LOCALE_TO_XKB_OVERRIDES[locale]
+        logging.debug("override for %s → %s",
+                      locale, xkb)
+        if xkb:
+            return xkb
+        else:
+            raise KeyError("layout %s explicitely disabled in overrides"
+                           % locale)
+    xkb_names = sorted(name_to_xkb.keys())
+    if name in xkb_names:
+        return name_to_xkb[name]
+    else:
+        logging.debug("name %s failed" % name)
+    for sub_name in name.split(' '):
+        if sub_name in xkb_names:
+            xkb = name_to_xkb[sub_name]
+            logging.debug("dumb mapping failed but match with locale word: "
+                          "%s (%s) → %s (%s)",
+                          locale, name, xkb, sub_name)
+            return xkb
+        else:
+            logging.debug("sub_name failed")
+    for xkb_name in xkb_names:
+        for xkb_sub_name in xkb_name.split(' '):
+            if xkb_sub_name.strip('()') == name:
+                xkb = name_to_xkb[xkb_name]
+                logging.debug("dumb mapping failed but match with xkb word: "
+                              "%s (%s) → %s (%s)",
+                              locale, name, xkb, xkb_name)
+                return xkb
+    raise KeyError("failed to find XKB mapping for %s" % locale)
+
+
+def convert_file(source_file, destination_path):
+    logging.info("Parsing %s", source_file)
+
+    itree = xml.etree.ElementTree.ElementTree()
+    itree.parse(source_file)
+
+    root = convert_xml(itree)
+
+    try:
+        xkb_name = locale_to_xkb(root["locale"], root["name"])
+    except KeyError as e:
+        logging.warn(e)
+        return False
+    destination_file = os.path.join(destination_path, xkb_name + ".json")
+
+    with open(destination_file, 'w', encoding="utf-8") as dest_fd:
+        json.dump(root, dest_fd, ensure_ascii=False, indent=2, sort_keys=True)
+
+    logging.debug("written %s", destination_file)
+
+
+def load_xkb_mappings():
+    xkb = GnomeDesktop.XkbInfo()
+    layouts = xkb.get_all_layouts()
+    name_to_xkb = {}
+
+    for layout in layouts:
+        name = xkb.get_layout_info(layout).display_name
+        name_to_xkb[name] = layout
+
+    return name_to_xkb
+
+
+locale.setlocale(locale.LC_ALL, "C")
+name_to_xkb = load_xkb_mappings()
+
+
+if __name__ == "__main__":
+    if "DEBUG" in os.environ:
+        logging.basicConfig(level=logging.DEBUG)
+
+    if len(sys.argv) < 2:
+        print("supply a CLDR keyboard file")
+        sys.exit(1)
+
+    if len(sys.argv) < 3:
+        print("supply an output directory")
+        sys.exit(1)
+
+    source = sys.argv[1]
+    destination = sys.argv[2]
+    if os.path.isfile(source):
+        convert_file(source, destination)
+    elif os.path.isdir(source):
+        for path in glob.glob(source + "/*-t-k0-android.xml"):
+            convert_file(path, destination)
diff --git a/data/cldr2json/test/__init__.py b/data/cldr2json/test/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/data/cldr2json/test/data/fr-t-k0-android.xml b/data/cldr2json/test/data/fr-t-k0-android.xml
new file mode 100644 (file)
index 0000000..1e76b81
--- /dev/null
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE keyboard SYSTEM "../dtd/ldmlKeyboard.dtd">
+<keyboard locale="fr-t-k0-android">
+       <version platform="4.4" number="$Revision: 11914 $"/>
+       <names>
+               <name value="French"/>
+       </names>
+       <keyMap>
+               <map iso="D01" to="a" longPress="à â % æ á ä ã å ā ª"/> <!-- Q -->
+               <map iso="D02" to="z"/> <!-- W -->
+               <map iso="D03" to="e" longPress="é è ê ë % ę ė ē"/>
+               <map iso="D04" to="r"/>
+               <map iso="D05" to="t"/>
+               <map iso="D06" to="y" longPress="% ÿ"/>
+               <map iso="D07" to="u" longPress="ù û % ü ú ū"/>
+               <map iso="D08" to="i" longPress="î % ï ì í į ī"/>
+               <map iso="D09" to="o" longPress="ô œ % ö ò ó õ ø ō º"/>
+               <map iso="D10" to="p"/>
+               <map iso="C01" to="q"/> <!-- A -->
+               <map iso="C02" to="s"/>
+               <map iso="C03" to="d"/>
+               <map iso="C04" to="f"/>
+               <map iso="C05" to="g"/>
+               <map iso="C06" to="h"/>
+               <map iso="C07" to="j"/>
+               <map iso="C08" to="k"/>
+               <map iso="C09" to="l"/>
+               <map iso="C10" to="m"/> <!-- ; -->
+               <map iso="B01" to="w"/> <!-- Z -->
+               <map iso="B02" to="x"/>
+               <map iso="B03" to="c" longPress="ç ć č"/>
+               <map iso="B04" to="v"/>
+               <map iso="B05" to="b"/>
+               <map iso="B06" to="n"/>
+               <map iso="B07" to="&apos;" longPress="‘ ’ ‹ ›"/> <!-- M -->
+               <map iso="A02" to=","/> <!-- (key to left of space) -->
+               <map iso="A03" to=" "/> <!-- space -->
+               <map iso="A04" to="." longPress="# ! , ? - : ' @"/> <!-- (key to right of space) -->
+       </keyMap>
+       <keyMap modifiers="shift caps">
+               <map iso="D01" to="A" longPress="À Â % Æ Á Ä Ã Å Ā ª"/> <!-- Q -->
+               <map iso="D02" to="Z"/> <!-- W -->
+               <map iso="D03" to="E" longPress="É È Ê Ë % Ę Ė Ē"/>
+               <map iso="D04" to="R"/>
+               <map iso="D05" to="T"/>
+               <map iso="D06" to="Y" longPress="% Ÿ"/>
+               <map iso="D07" to="U" longPress="Ù Û % Ü Ú Ū"/>
+               <map iso="D08" to="I" longPress="Π% Ï Ì Í Į Ī"/>
+               <map iso="D09" to="O" longPress="Ô Œ % Ö Ò Ó Õ Ø Ō º"/>
+               <map iso="D10" to="P"/>
+               <map iso="C01" to="Q"/> <!-- A -->
+               <map iso="C02" to="S"/>
+               <map iso="C03" to="D"/>
+               <map iso="C04" to="F"/>
+               <map iso="C05" to="G"/>
+               <map iso="C06" to="H"/>
+               <map iso="C07" to="J"/>
+               <map iso="C08" to="K"/>
+               <map iso="C09" to="L"/>
+               <map iso="C10" to="M"/> <!-- ; -->
+               <map iso="B01" to="W"/> <!-- Z -->
+               <map iso="B02" to="X"/>
+               <map iso="B03" to="C" longPress="Ç Ć Č"/>
+               <map iso="B04" to="V"/>
+               <map iso="B05" to="B"/>
+               <map iso="B06" to="N"/>
+               <map iso="B07" to="&apos;" longPress="‘ ’ ‹ ›"/> <!-- M -->
+               <map iso="A02" to=","/> <!-- (key to left of space) -->
+               <map iso="A03" to=" "/> <!-- space -->
+               <map iso="A04" to="." longPress="# ! , ? - : ' @"/> <!-- (key to right of space) -->
+       </keyMap>
+       <keyMap modifiers="opt">
+               <map iso="D01" to="1" longPress="¹ ½ ⅓ ¼ ⅛"/> <!-- Q  base=a -->
+               <map iso="D02" to="2" longPress="² ⅔"/> <!-- W  base=z -->
+               <map iso="D03" to="3" longPress="³ ¾ ⅜"/> <!-- E -->
+               <map iso="D04" to="4" longPress="⁴"/> <!-- R -->
+               <map iso="D05" to="5" longPress="⅝"/> <!-- T -->
+               <map iso="D06" to="6"/> <!-- Y -->
+               <map iso="D07" to="7" longPress="⅞"/> <!-- U -->
+               <map iso="D08" to="8"/> <!-- I -->
+               <map iso="D09" to="9"/> <!-- O -->
+               <map iso="D10" to="0" longPress="ⁿ ∅"/> <!-- P -->
+               <map iso="C01" to="@"/> <!-- A  base=q -->
+               <map iso="C02" to="#"/> <!-- S -->
+               <map iso="C03" to="€" longPress="¢ £ $ ¥ ₱"/> <!-- D -->
+               <map iso="C04" to="%" longPress="‰"/> <!-- F -->
+               <map iso="C05" to="&amp;"/> <!-- G -->
+               <map iso="C06" to="-" longPress="_ – — ·"/> <!-- H -->
+               <map iso="C07" to="+" longPress="±"/> <!-- J -->
+               <map iso="C08" to="(" longPress="&lt; { ["/> <!-- K -->
+               <map iso="C09" to=")" longPress="&gt; } ]"/> <!-- L -->
+               <map iso="B01" to="*" longPress="† ‡ ★"/> <!-- Z  base=w -->
+               <map iso="B02" to="\u{22}" longPress="“ ” « »"/> <!-- X  to= "  -->
+               <map iso="B03" to="&apos;" longPress="‘ ’ ‹ ›"/> <!-- C -->
+               <map iso="B04" to=":"/> <!-- V -->
+               <map iso="B05" to=";"/> <!-- B -->
+               <map iso="B06" to="!" longPress="¡"/> <!-- N -->
+               <map iso="B07" to="?" longPress="¿"/> <!-- M  base=' -->
+               <map iso="A00" to="_"/> <!-- (3 keys to left of space) -->
+               <map iso="A01" to="/"/> <!-- (2 keys to left of space) -->
+               <map iso="A02" to=" "/> <!-- (key to left of space)  base=, -->
+               <map iso="A03" to=","/> <!-- space -->
+               <map iso="A04" to="." longPress="…"/> <!-- (key to right of space) -->
+       </keyMap>
+       <keyMap modifiers="opt+shift">
+               <map iso="D01" to="~"/> <!-- Q  base=a -->
+               <map iso="D02" to="`"/> <!-- W  base=z -->
+               <map iso="D03" to="|"/> <!-- E -->
+               <map iso="D04" to="•" longPress="♪ ♥ ♠ ♦ ♣"/> <!-- R -->
+               <map iso="D05" to="√"/> <!-- T -->
+               <map iso="D06" to="Π" longPress="π"/> <!-- Y -->
+               <map iso="D07" to="÷"/> <!-- U -->
+               <map iso="D08" to="×"/> <!-- I -->
+               <map iso="D09" to="¶" longPress="§"/> <!-- O -->
+               <map iso="D10" to="∆"/> <!-- P -->
+               <map iso="C01" to="£"/> <!-- A  base=q -->
+               <map iso="C02" to="¥"/> <!-- S -->
+               <map iso="C03" to="$" longPress="¢"/> <!-- D -->
+               <map iso="C04" to="¢"/> <!-- F -->
+               <map iso="C05" to="^" longPress="↑ ↓ ← →"/> <!-- G -->
+               <map iso="C06" to="°" longPress="′ ″"/> <!-- H -->
+               <map iso="C07" to="=" longPress="≠ ≈ ∞"/> <!-- J -->
+               <map iso="C08" to="{"/> <!-- K -->
+               <map iso="C09" to="}"/> <!-- L -->
+               <map iso="B01" to="\"/> <!-- Z  base=w -->
+               <map iso="B02" to="©"/> <!-- X -->
+               <map iso="B03" to="®"/> <!-- C -->
+               <map iso="B04" to="™"/> <!-- V -->
+               <map iso="B05" to="℅"/> <!-- B -->
+               <map iso="B06" to="["/> <!-- N -->
+               <map iso="B07" to="]"/> <!-- M  base=' -->
+               <map iso="A00" to="&lt;" longPress="‹ ≤ «"/> <!-- (3 keys to left of space) -->
+               <map iso="A01" to="&gt;" longPress="› ≥ »"/> <!-- (2 keys to left of space) -->
+               <map iso="A02" to=" "/> <!-- (key to left of space)  base=, -->
+               <map iso="A03" to=","/> <!-- space -->
+               <map iso="A04" to="." longPress="…"/> <!-- (key to right of space) -->
+       </keyMap>
+</keyboard>
diff --git a/data/cldr2json/test/data/fr.json b/data/cldr2json/test/data/fr.json
new file mode 100644 (file)
index 0000000..3a8949f
--- /dev/null
@@ -0,0 +1,614 @@
+{
+  "levels": [
+    {
+      "level": "",
+      "mode": "default",
+      "rows": [
+        [
+          [
+            "a",
+            "à",
+            "â",
+            "%",
+            "æ",
+            "á",
+            "ä",
+            "ã",
+            "å",
+            "ā",
+            "ª"
+          ],
+          [
+            "z"
+          ],
+          [
+            "e",
+            "é",
+            "è",
+            "ê",
+            "ë",
+            "%",
+            "ę",
+            "ė",
+            "ē"
+          ],
+          [
+            "r"
+          ],
+          [
+            "t"
+          ],
+          [
+            "y",
+            "%",
+            "ÿ"
+          ],
+          [
+            "u",
+            "ù",
+            "û",
+            "%",
+            "ü",
+            "ú",
+            "ū"
+          ],
+          [
+            "i",
+            "î",
+            "%",
+            "ï",
+            "ì",
+            "í",
+            "į",
+            "ī"
+          ],
+          [
+            "o",
+            "ô",
+            "œ",
+            "%",
+            "ö",
+            "ò",
+            "ó",
+            "õ",
+            "ø",
+            "ō",
+            "º"
+          ],
+          [
+            "p"
+          ]
+        ],
+        [
+          [
+            "q"
+          ],
+          [
+            "s"
+          ],
+          [
+            "d"
+          ],
+          [
+            "f"
+          ],
+          [
+            "g"
+          ],
+          [
+            "h"
+          ],
+          [
+            "j"
+          ],
+          [
+            "k"
+          ],
+          [
+            "l"
+          ],
+          [
+            "m"
+          ]
+        ],
+        [
+          [
+            "w"
+          ],
+          [
+            "x"
+          ],
+          [
+            "c",
+            "ç",
+            "ć",
+            "č"
+          ],
+          [
+            "v"
+          ],
+          [
+            "b"
+          ],
+          [
+            "n"
+          ],
+          [
+            "'",
+            "‘",
+            "’",
+            "‹",
+            "›"
+          ]
+        ],
+        [
+          [
+            ","
+          ],
+          [
+            " "
+          ],
+          [
+            ".",
+            "#",
+            "!",
+            ",",
+            "?",
+            "-",
+            ":",
+            "'",
+            "@"
+          ]
+        ]
+      ]
+    },
+    {
+      "level": "shift",
+      "mode": "latched",
+      "rows": [
+        [
+          [
+            "A",
+            "À",
+            "Â",
+            "%",
+            "Æ",
+            "Á",
+            "Ä",
+            "Ã",
+            "Å",
+            "Ā",
+            "ª"
+          ],
+          [
+            "Z"
+          ],
+          [
+            "E",
+            "É",
+            "È",
+            "Ê",
+            "Ë",
+            "%",
+            "Ę",
+            "Ė",
+            "Ē"
+          ],
+          [
+            "R"
+          ],
+          [
+            "T"
+          ],
+          [
+            "Y",
+            "%",
+            "Ÿ"
+          ],
+          [
+            "U",
+            "Ù",
+            "Û",
+            "%",
+            "Ü",
+            "Ú",
+            "Ū"
+          ],
+          [
+            "I",
+            "Î",
+            "%",
+            "Ï",
+            "Ì",
+            "Í",
+            "Į",
+            "Ī"
+          ],
+          [
+            "O",
+            "Ô",
+            "Œ",
+            "%",
+            "Ö",
+            "Ò",
+            "Ó",
+            "Õ",
+            "Ø",
+            "Ō",
+            "º"
+          ],
+          [
+            "P"
+          ]
+        ],
+        [
+          [
+            "Q"
+          ],
+          [
+            "S"
+          ],
+          [
+            "D"
+          ],
+          [
+            "F"
+          ],
+          [
+            "G"
+          ],
+          [
+            "H"
+          ],
+          [
+            "J"
+          ],
+          [
+            "K"
+          ],
+          [
+            "L"
+          ],
+          [
+            "M"
+          ]
+        ],
+        [
+          [
+            "W"
+          ],
+          [
+            "X"
+          ],
+          [
+            "C",
+            "Ç",
+            "Ć",
+            "Č"
+          ],
+          [
+            "V"
+          ],
+          [
+            "B"
+          ],
+          [
+            "N"
+          ],
+          [
+            "'",
+            "‘",
+            "’",
+            "‹",
+            "›"
+          ]
+        ],
+        [
+          [
+            ","
+          ],
+          [
+            " "
+          ],
+          [
+            ".",
+            "#",
+            "!",
+            ",",
+            "?",
+            "-",
+            ":",
+            "'",
+            "@"
+          ]
+        ]
+      ]
+    },
+    {
+      "level": "opt",
+      "mode": "locked",
+      "rows": [
+        [
+          [
+            "1",
+            "¹",
+            "½",
+            "⅓",
+            "¼",
+            "⅛"
+          ],
+          [
+            "2",
+            "²",
+            "⅔"
+          ],
+          [
+            "3",
+            "³",
+            "¾",
+            "⅜"
+          ],
+          [
+            "4",
+            "⁴"
+          ],
+          [
+            "5",
+            "⅝"
+          ],
+          [
+            "6"
+          ],
+          [
+            "7",
+            "⅞"
+          ],
+          [
+            "8"
+          ],
+          [
+            "9"
+          ],
+          [
+            "0",
+            "ⁿ",
+            "∅"
+          ]
+        ],
+        [
+          [
+            "@"
+          ],
+          [
+            "#"
+          ],
+          [
+            "€",
+            "¢",
+            "£",
+            "$",
+            "¥",
+            "₱"
+          ],
+          [
+            "%",
+            "‰"
+          ],
+          [
+            "&"
+          ],
+          [
+            "-",
+            "_",
+            "–",
+            "—",
+            "·"
+          ],
+          [
+            "+",
+            "±"
+          ],
+          [
+            "(",
+            "<",
+            "{",
+            "["
+          ],
+          [
+            ")",
+            ">",
+            "}",
+            "]"
+          ]
+        ],
+        [
+          [
+            "*",
+            "†",
+            "‡",
+            "★"
+          ],
+          [
+            "\"",
+            "“",
+            "”",
+            "«",
+            "»"
+          ],
+          [
+            "'",
+            "‘",
+            "’",
+            "‹",
+            "›"
+          ],
+          [
+            ":"
+          ],
+          [
+            ";"
+          ],
+          [
+            "!",
+            "¡"
+          ],
+          [
+            "?",
+            "¿"
+          ]
+        ],
+        [
+          [
+            "_"
+          ],
+          [
+            "/"
+          ],
+          [
+            " "
+          ],
+          [
+            ","
+          ],
+          [
+            ".",
+            "…"
+          ]
+        ]
+      ]
+    },
+    {
+      "level": "opt+shift",
+      "mode": "locked",
+      "rows": [
+        [
+          [
+            "~"
+          ],
+          [
+            "`"
+          ],
+          [
+            "|"
+          ],
+          [
+            "•",
+            "♪",
+            "♥",
+            "♠",
+            "♦",
+            "♣"
+          ],
+          [
+            "√"
+          ],
+          [
+            "Π",
+            "π"
+          ],
+          [
+            "÷"
+          ],
+          [
+            "×"
+          ],
+          [
+            "¶",
+            "§"
+          ],
+          [
+            "∆"
+          ]
+        ],
+        [
+          [
+            "£"
+          ],
+          [
+            "¥"
+          ],
+          [
+            "$",
+            "¢"
+          ],
+          [
+            "¢"
+          ],
+          [
+            "^",
+            "↑",
+            "↓",
+            "←",
+            "→"
+          ],
+          [
+            "°",
+            "′",
+            "″"
+          ],
+          [
+            "=",
+            "≠",
+            "≈",
+            "∞"
+          ],
+          [
+            "{"
+          ],
+          [
+            "}"
+          ]
+        ],
+        [
+          [
+            "\\"
+          ],
+          [
+            "©"
+          ],
+          [
+            "®"
+          ],
+          [
+            "™"
+          ],
+          [
+            "℅"
+          ],
+          [
+            "["
+          ],
+          [
+            "]"
+          ]
+        ],
+        [
+          [
+            "<",
+            "‹",
+            "≤",
+            "«"
+          ],
+          [
+            ">",
+            "›",
+            "≥",
+            "»"
+          ],
+          [
+            " "
+          ],
+          [
+            ","
+          ],
+          [
+            ".",
+            "…"
+          ]
+        ]
+      ]
+    }
+  ],
+  "locale": "fr",
+  "name": "French"
+}
diff --git a/data/cldr2json/test/test_cldr2json.py b/data/cldr2json/test/test_cldr2json.py
new file mode 100755 (executable)
index 0000000..78a6aa0
--- /dev/null
@@ -0,0 +1,212 @@
+#!/usr/bin/python3
+
+import json
+import tempfile
+import unittest
+import xml.etree.ElementTree
+
+import cldr2json
+
+
+class TestParseSingleKey(unittest.TestCase):
+    def test_ascii(self):
+        self.assertEqual(cldr2json.parse_single_key("a"), "a")
+
+    def test_nonascii(self):
+        self.assertEqual(cldr2json.parse_single_key("Æ"), "Æ")
+
+    def test_twochars(self):
+        self.assertEqual(cldr2json.parse_single_key("ԵՒ"), "ԵՒ")
+
+    def test_decode(self):
+        self.assertEqual(cldr2json.parse_single_key("\\u{200D}"), "\u200d")
+
+    def test_decode_threechars(self):
+        self.assertEqual(cldr2json.parse_single_key("ज\\u{94D}ञ"), "ज\u094Dञ")
+
+
+class TestParseRow(unittest.TestCase):
+    def test_parse_row(self):
+        xml_string = """
+        <keyMap>
+            <map iso="D01" to="a" longPress="à â % æ á ä ã å ā ª"/> <!-- Q -->
+            <map iso="D02" to="z"/> <!-- W -->
+            <map iso="D03" to="e" longPress="é è ê ë % ę ė ē"/>
+            <map iso="D04" to="r"/>
+            <map iso="D05" to="t"/>
+            <map iso="D06" to="y" longPress="% ÿ"/>
+            <map iso="D07" to="u" longPress="ù û % ü ú ū"/>
+            <map iso="D08" to="i" longPress="î % ï ì í į ī"/>
+            <map iso="D09" to="o" longPress="ô œ % ö ò ó õ ø ō º"/>
+            <map iso="D10" to="p"/>
+            <map iso="C01" to="q"/> <!-- A -->
+            <map iso="C02" to="s"/>
+            <map iso="C03" to="d"/>
+            <map iso="C04" to="f"/>
+            <map iso="C05" to="g"/>
+            <map iso="C06" to="h"/>
+            <map iso="C07" to="j"/>
+            <map iso="C08" to="k"/>
+            <map iso="C09" to="l"/>
+            <map iso="C10" to="m"/> <!-- ; -->
+            <map iso="B01" to="w"/> <!-- Z -->
+            <map iso="B02" to="x"/>
+            <map iso="B03" to="c" longPress="ç ć č"/>
+            <map iso="B04" to="v"/>
+            <map iso="B05" to="b"/>
+            <map iso="B06" to="n"/>
+            <map iso="B07" to="&apos;" longPress="‘ ’ ‹ ›"/> <!-- M -->
+            <map iso="A02" to=","/> <!-- (key to left of space) -->
+            <map iso="A03" to=" "/> <!-- space -->
+            <map iso="A04" to="." longPress="# ! , ? - : ' @"/> <!-- (key to right of space) -->
+        </keyMap>
+        """
+        xml_tree = xml.etree.ElementTree.XML(xml_string)
+        json = [[
+                 ['a', 'à', 'â', '%', 'æ', 'á', 'ä', 'ã', 'å', 'ā', 'ª'],
+                 ['z'],
+                 ['e', 'é', 'è', 'ê', 'ë', '%', 'ę', 'ė', 'ē'],
+                 ['r'],
+                 ['t'],
+                 ['y', '%', 'ÿ'],
+                 ['u', 'ù', 'û', '%', 'ü', 'ú', 'ū'],
+                 ['i', 'î', '%', 'ï', 'ì', 'í', 'į', 'ī'],
+                 ['o', 'ô', 'œ', '%', 'ö', 'ò', 'ó', 'õ', 'ø', 'ō', 'º'],
+                 ['p']
+                ], [
+                 ['q'],
+                 ['s'],
+                 ['d'],
+                 ['f'],
+                 ['g'],
+                 ['h'],
+                 ['j'],
+                 ['k'],
+                 ['l'],
+                 ['m']
+                ], [
+                 ['w'],
+                 ['x'],
+                 ['c', 'ç', 'ć', 'č'],
+                 ['v'],
+                 ['b'],
+                 ['n'],
+                 ["'", '‘', '’', '‹', '›']
+                ], [
+                 [','],
+                 [' '],
+                 ['.', '#', '!', ',', '?', '-', ':', "'", '@']
+                ]]
+        self.assertEqual(cldr2json.parse_rows(xml_tree), json)
+
+
+class TestConvertXml(unittest.TestCase):
+    def test_convert_xml(self):
+        xml_string = """<?xml version="1.0" encoding="UTF-8" ?>
+        <!DOCTYPE keyboard SYSTEM "../dtd/ldmlKeyboard.dtd">
+        <keyboard locale="fr-t-k0-android">
+            <version platform="4.4" number="$Revision: 11914 $"/>
+            <names>
+                <name value="French"/>
+            </names>
+            <keyMap>
+                <map iso="D01" to="a" longPress="à â % æ á ä ã å ā ª"/> <!-- Q -->
+            </keyMap>
+            <keyMap modifiers="shift caps">
+                <map iso="D01" to="A" longPress="À Â % Æ Á Ä Ã Å Ā ª"/> <!-- Q -->
+            </keyMap>
+            <keyMap modifiers="opt">
+                <map iso="D01" to="1" longPress="¹ ½ ⅓ ¼ ⅛"/> <!-- Q  base=a -->
+            </keyMap>
+            <keyMap modifiers="opt+shift">
+                <map iso="D01" to="~"/> <!-- Q  base=a -->
+            </keyMap>
+        </keyboard>
+        """
+        xml_tree = xml.etree.ElementTree.XML(xml_string)
+        json = {
+          "locale": "fr",
+          "name": "French",
+          "levels": [
+            {
+              "level": "",
+              "mode": "default",
+              "rows": [
+                [
+                  ['a', 'à', 'â', '%', 'æ', 'á', 'ä', 'ã', 'å', 'ā', 'ª'],
+                ]
+              ]
+            },
+            {
+              "level": "shift",
+              "mode": "latched",
+              "rows": [
+                [
+                  ['A', 'À', 'Â', '%', 'Æ', 'Á', 'Ä', 'Ã', 'Å', 'Ā', 'ª'],
+                ]
+              ]
+            },
+            {
+              "level": "opt",
+              "mode": "locked",
+              "rows": [
+                [
+                  ["1", "¹", "½", "⅓", "¼", "⅛"],
+                ]
+              ]
+            },
+            {
+              "level": "opt+shift",
+              "mode": "locked",
+              "rows": [
+                [
+                  ["~"],
+                ]
+              ]
+            }
+          ]
+        }
+        self.assertEqual(cldr2json.convert_xml(xml_tree), json)
+
+
+class TestConvertFile(unittest.TestCase):
+    def test_fr(self):
+        outdir = tempfile.mkdtemp()
+        cldr2json.convert_file("test/data/fr-t-k0-android.xml", outdir)
+        with open("test/data/fr.json", encoding="utf-8") as expected_json_fd:
+            expected_json = json.load(expected_json_fd)
+        with open(outdir + "/fr.json", encoding="utf-8") as actual_json_fd:
+            actual_json = json.load(actual_json_fd)
+        self.assertEqual(expected_json, actual_json)
+
+
+class TestLocaleToXKB(unittest.TestCase):
+    def test_simple(self):
+        self.assertEqual(cldr2json.locale_to_xkb("fr", "French"),
+                         "fr")
+
+    def test_fallback(self):
+        self.assertEqual(cldr2json.locale_to_xkb("nb", "Norwegian Bokmål"),
+                         "no")
+
+    def test_fallback2(self):
+        self.assertEqual(cldr2json.locale_to_xkb("km", "Khmer"),
+                         "kh")
+
+    def test_override(self):
+        self.assertEqual(cldr2json.locale_to_xkb("en-GB",
+                                                 "English Great Britain"),
+                         "uk")
+
+
+class LoadXKBMapplings(unittest.TestCase):
+    def test_dictionnary(self):
+        self.assertIsInstance(cldr2json.load_xkb_mappings(), dict)
+
+    def test_mapping(self):
+        mapping = cldr2json.load_xkb_mappings()
+        self.assertEqual(mapping["French"], "fr")
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/test/__init__.py b/test/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/test/data/fr-t-k0-android.xml b/test/data/fr-t-k0-android.xml
deleted file mode 100644 (file)
index 1e76b81..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!DOCTYPE keyboard SYSTEM "../dtd/ldmlKeyboard.dtd">
-<keyboard locale="fr-t-k0-android">
-       <version platform="4.4" number="$Revision: 11914 $"/>
-       <names>
-               <name value="French"/>
-       </names>
-       <keyMap>
-               <map iso="D01" to="a" longPress="à â % æ á ä ã å ā ª"/> <!-- Q -->
-               <map iso="D02" to="z"/> <!-- W -->
-               <map iso="D03" to="e" longPress="é è ê ë % ę ė ē"/>
-               <map iso="D04" to="r"/>
-               <map iso="D05" to="t"/>
-               <map iso="D06" to="y" longPress="% ÿ"/>
-               <map iso="D07" to="u" longPress="ù û % ü ú ū"/>
-               <map iso="D08" to="i" longPress="î % ï ì í į ī"/>
-               <map iso="D09" to="o" longPress="ô œ % ö ò ó õ ø ō º"/>
-               <map iso="D10" to="p"/>
-               <map iso="C01" to="q"/> <!-- A -->
-               <map iso="C02" to="s"/>
-               <map iso="C03" to="d"/>
-               <map iso="C04" to="f"/>
-               <map iso="C05" to="g"/>
-               <map iso="C06" to="h"/>
-               <map iso="C07" to="j"/>
-               <map iso="C08" to="k"/>
-               <map iso="C09" to="l"/>
-               <map iso="C10" to="m"/> <!-- ; -->
-               <map iso="B01" to="w"/> <!-- Z -->
-               <map iso="B02" to="x"/>
-               <map iso="B03" to="c" longPress="ç ć č"/>
-               <map iso="B04" to="v"/>
-               <map iso="B05" to="b"/>
-               <map iso="B06" to="n"/>
-               <map iso="B07" to="&apos;" longPress="‘ ’ ‹ ›"/> <!-- M -->
-               <map iso="A02" to=","/> <!-- (key to left of space) -->
-               <map iso="A03" to=" "/> <!-- space -->
-               <map iso="A04" to="." longPress="# ! , ? - : ' @"/> <!-- (key to right of space) -->
-       </keyMap>
-       <keyMap modifiers="shift caps">
-               <map iso="D01" to="A" longPress="À Â % Æ Á Ä Ã Å Ā ª"/> <!-- Q -->
-               <map iso="D02" to="Z"/> <!-- W -->
-               <map iso="D03" to="E" longPress="É È Ê Ë % Ę Ė Ē"/>
-               <map iso="D04" to="R"/>
-               <map iso="D05" to="T"/>
-               <map iso="D06" to="Y" longPress="% Ÿ"/>
-               <map iso="D07" to="U" longPress="Ù Û % Ü Ú Ū"/>
-               <map iso="D08" to="I" longPress="Π% Ï Ì Í Į Ī"/>
-               <map iso="D09" to="O" longPress="Ô Œ % Ö Ò Ó Õ Ø Ō º"/>
-               <map iso="D10" to="P"/>
-               <map iso="C01" to="Q"/> <!-- A -->
-               <map iso="C02" to="S"/>
-               <map iso="C03" to="D"/>
-               <map iso="C04" to="F"/>
-               <map iso="C05" to="G"/>
-               <map iso="C06" to="H"/>
-               <map iso="C07" to="J"/>
-               <map iso="C08" to="K"/>
-               <map iso="C09" to="L"/>
-               <map iso="C10" to="M"/> <!-- ; -->
-               <map iso="B01" to="W"/> <!-- Z -->
-               <map iso="B02" to="X"/>
-               <map iso="B03" to="C" longPress="Ç Ć Č"/>
-               <map iso="B04" to="V"/>
-               <map iso="B05" to="B"/>
-               <map iso="B06" to="N"/>
-               <map iso="B07" to="&apos;" longPress="‘ ’ ‹ ›"/> <!-- M -->
-               <map iso="A02" to=","/> <!-- (key to left of space) -->
-               <map iso="A03" to=" "/> <!-- space -->
-               <map iso="A04" to="." longPress="# ! , ? - : ' @"/> <!-- (key to right of space) -->
-       </keyMap>
-       <keyMap modifiers="opt">
-               <map iso="D01" to="1" longPress="¹ ½ ⅓ ¼ ⅛"/> <!-- Q  base=a -->
-               <map iso="D02" to="2" longPress="² ⅔"/> <!-- W  base=z -->
-               <map iso="D03" to="3" longPress="³ ¾ ⅜"/> <!-- E -->
-               <map iso="D04" to="4" longPress="⁴"/> <!-- R -->
-               <map iso="D05" to="5" longPress="⅝"/> <!-- T -->
-               <map iso="D06" to="6"/> <!-- Y -->
-               <map iso="D07" to="7" longPress="⅞"/> <!-- U -->
-               <map iso="D08" to="8"/> <!-- I -->
-               <map iso="D09" to="9"/> <!-- O -->
-               <map iso="D10" to="0" longPress="ⁿ ∅"/> <!-- P -->
-               <map iso="C01" to="@"/> <!-- A  base=q -->
-               <map iso="C02" to="#"/> <!-- S -->
-               <map iso="C03" to="€" longPress="¢ £ $ ¥ ₱"/> <!-- D -->
-               <map iso="C04" to="%" longPress="‰"/> <!-- F -->
-               <map iso="C05" to="&amp;"/> <!-- G -->
-               <map iso="C06" to="-" longPress="_ – — ·"/> <!-- H -->
-               <map iso="C07" to="+" longPress="±"/> <!-- J -->
-               <map iso="C08" to="(" longPress="&lt; { ["/> <!-- K -->
-               <map iso="C09" to=")" longPress="&gt; } ]"/> <!-- L -->
-               <map iso="B01" to="*" longPress="† ‡ ★"/> <!-- Z  base=w -->
-               <map iso="B02" to="\u{22}" longPress="“ ” « »"/> <!-- X  to= "  -->
-               <map iso="B03" to="&apos;" longPress="‘ ’ ‹ ›"/> <!-- C -->
-               <map iso="B04" to=":"/> <!-- V -->
-               <map iso="B05" to=";"/> <!-- B -->
-               <map iso="B06" to="!" longPress="¡"/> <!-- N -->
-               <map iso="B07" to="?" longPress="¿"/> <!-- M  base=' -->
-               <map iso="A00" to="_"/> <!-- (3 keys to left of space) -->
-               <map iso="A01" to="/"/> <!-- (2 keys to left of space) -->
-               <map iso="A02" to=" "/> <!-- (key to left of space)  base=, -->
-               <map iso="A03" to=","/> <!-- space -->
-               <map iso="A04" to="." longPress="…"/> <!-- (key to right of space) -->
-       </keyMap>
-       <keyMap modifiers="opt+shift">
-               <map iso="D01" to="~"/> <!-- Q  base=a -->
-               <map iso="D02" to="`"/> <!-- W  base=z -->
-               <map iso="D03" to="|"/> <!-- E -->
-               <map iso="D04" to="•" longPress="♪ ♥ ♠ ♦ ♣"/> <!-- R -->
-               <map iso="D05" to="√"/> <!-- T -->
-               <map iso="D06" to="Π" longPress="π"/> <!-- Y -->
-               <map iso="D07" to="÷"/> <!-- U -->
-               <map iso="D08" to="×"/> <!-- I -->
-               <map iso="D09" to="¶" longPress="§"/> <!-- O -->
-               <map iso="D10" to="∆"/> <!-- P -->
-               <map iso="C01" to="£"/> <!-- A  base=q -->
-               <map iso="C02" to="¥"/> <!-- S -->
-               <map iso="C03" to="$" longPress="¢"/> <!-- D -->
-               <map iso="C04" to="¢"/> <!-- F -->
-               <map iso="C05" to="^" longPress="↑ ↓ ← →"/> <!-- G -->
-               <map iso="C06" to="°" longPress="′ ″"/> <!-- H -->
-               <map iso="C07" to="=" longPress="≠ ≈ ∞"/> <!-- J -->
-               <map iso="C08" to="{"/> <!-- K -->
-               <map iso="C09" to="}"/> <!-- L -->
-               <map iso="B01" to="\"/> <!-- Z  base=w -->
-               <map iso="B02" to="©"/> <!-- X -->
-               <map iso="B03" to="®"/> <!-- C -->
-               <map iso="B04" to="™"/> <!-- V -->
-               <map iso="B05" to="℅"/> <!-- B -->
-               <map iso="B06" to="["/> <!-- N -->
-               <map iso="B07" to="]"/> <!-- M  base=' -->
-               <map iso="A00" to="&lt;" longPress="‹ ≤ «"/> <!-- (3 keys to left of space) -->
-               <map iso="A01" to="&gt;" longPress="› ≥ »"/> <!-- (2 keys to left of space) -->
-               <map iso="A02" to=" "/> <!-- (key to left of space)  base=, -->
-               <map iso="A03" to=","/> <!-- space -->
-               <map iso="A04" to="." longPress="…"/> <!-- (key to right of space) -->
-       </keyMap>
-</keyboard>
diff --git a/test/data/fr.json b/test/data/fr.json
deleted file mode 100644 (file)
index 3a8949f..0000000
+++ /dev/null
@@ -1,614 +0,0 @@
-{
-  "levels": [
-    {
-      "level": "",
-      "mode": "default",
-      "rows": [
-        [
-          [
-            "a",
-            "à",
-            "â",
-            "%",
-            "æ",
-            "á",
-            "ä",
-            "ã",
-            "å",
-            "ā",
-            "ª"
-          ],
-          [
-            "z"
-          ],
-          [
-            "e",
-            "é",
-            "è",
-            "ê",
-            "ë",
-            "%",
-            "ę",
-            "ė",
-            "ē"
-          ],
-          [
-            "r"
-          ],
-          [
-            "t"
-          ],
-          [
-            "y",
-            "%",
-            "ÿ"
-          ],
-          [
-            "u",
-            "ù",
-            "û",
-            "%",
-            "ü",
-            "ú",
-            "ū"
-          ],
-          [
-            "i",
-            "î",
-            "%",
-            "ï",
-            "ì",
-            "í",
-            "į",
-            "ī"
-          ],
-          [
-            "o",
-            "ô",
-            "œ",
-            "%",
-            "ö",
-            "ò",
-            "ó",
-            "õ",
-            "ø",
-            "ō",
-            "º"
-          ],
-          [
-            "p"
-          ]
-        ],
-        [
-          [
-            "q"
-          ],
-          [
-            "s"
-          ],
-          [
-            "d"
-          ],
-          [
-            "f"
-          ],
-          [
-            "g"
-          ],
-          [
-            "h"
-          ],
-          [
-            "j"
-          ],
-          [
-            "k"
-          ],
-          [
-            "l"
-          ],
-          [
-            "m"
-          ]
-        ],
-        [
-          [
-            "w"
-          ],
-          [
-            "x"
-          ],
-          [
-            "c",
-            "ç",
-            "ć",
-            "č"
-          ],
-          [
-            "v"
-          ],
-          [
-            "b"
-          ],
-          [
-            "n"
-          ],
-          [
-            "'",
-            "‘",
-            "’",
-            "‹",
-            "›"
-          ]
-        ],
-        [
-          [
-            ","
-          ],
-          [
-            " "
-          ],
-          [
-            ".",
-            "#",
-            "!",
-            ",",
-            "?",
-            "-",
-            ":",
-            "'",
-            "@"
-          ]
-        ]
-      ]
-    },
-    {
-      "level": "shift",
-      "mode": "latched",
-      "rows": [
-        [
-          [
-            "A",
-            "À",
-            "Â",
-            "%",
-            "Æ",
-            "Á",
-            "Ä",
-            "Ã",
-            "Å",
-            "Ā",
-            "ª"
-          ],
-          [
-            "Z"
-          ],
-          [
-            "E",
-            "É",
-            "È",
-            "Ê",
-            "Ë",
-            "%",
-            "Ę",
-            "Ė",
-            "Ē"
-          ],
-          [
-            "R"
-          ],
-          [
-            "T"
-          ],
-          [
-            "Y",
-            "%",
-            "Ÿ"
-          ],
-          [
-            "U",
-            "Ù",
-            "Û",
-            "%",
-            "Ü",
-            "Ú",
-            "Ū"
-          ],
-          [
-            "I",
-            "Î",
-            "%",
-            "Ï",
-            "Ì",
-            "Í",
-            "Į",
-            "Ī"
-          ],
-          [
-            "O",
-            "Ô",
-            "Œ",
-            "%",
-            "Ö",
-            "Ò",
-            "Ó",
-            "Õ",
-            "Ø",
-            "Ō",
-            "º"
-          ],
-          [
-            "P"
-          ]
-        ],
-        [
-          [
-            "Q"
-          ],
-          [
-            "S"
-          ],
-          [
-            "D"
-          ],
-          [
-            "F"
-          ],
-          [
-            "G"
-          ],
-          [
-            "H"
-          ],
-          [
-            "J"
-          ],
-          [
-            "K"
-          ],
-          [
-            "L"
-          ],
-          [
-            "M"
-          ]
-        ],
-        [
-          [
-            "W"
-          ],
-          [
-            "X"
-          ],
-          [
-            "C",
-            "Ç",
-            "Ć",
-            "Č"
-          ],
-          [
-            "V"
-          ],
-          [
-            "B"
-          ],
-          [
-            "N"
-          ],
-          [
-            "'",
-            "‘",
-            "’",
-            "‹",
-            "›"
-          ]
-        ],
-        [
-          [
-            ","
-          ],
-          [
-            " "
-          ],
-          [
-            ".",
-            "#",
-            "!",
-            ",",
-            "?",
-            "-",
-            ":",
-            "'",
-            "@"
-          ]
-        ]
-      ]
-    },
-    {
-      "level": "opt",
-      "mode": "locked",
-      "rows": [
-        [
-          [
-            "1",
-            "¹",
-            "½",
-            "⅓",
-            "¼",
-            "⅛"
-          ],
-          [
-            "2",
-            "²",
-            "⅔"
-          ],
-          [
-            "3",
-            "³",
-            "¾",
-            "⅜"
-          ],
-          [
-            "4",
-            "⁴"
-          ],
-          [
-            "5",
-            "⅝"
-          ],
-          [
-            "6"
-          ],
-          [
-            "7",
-            "⅞"
-          ],
-          [
-            "8"
-          ],
-          [
-            "9"
-          ],
-          [
-            "0",
-            "ⁿ",
-            "∅"
-          ]
-        ],
-        [
-          [
-            "@"
-          ],
-          [
-            "#"
-          ],
-          [
-            "€",
-            "¢",
-            "£",
-            "$",
-            "¥",
-            "₱"
-          ],
-          [
-            "%",
-            "‰"
-          ],
-          [
-            "&"
-          ],
-          [
-            "-",
-            "_",
-            "–",
-            "—",
-            "·"
-          ],
-          [
-            "+",
-            "±"
-          ],
-          [
-            "(",
-            "<",
-            "{",
-            "["
-          ],
-          [
-            ")",
-            ">",
-            "}",
-            "]"
-          ]
-        ],
-        [
-          [
-            "*",
-            "†",
-            "‡",
-            "★"
-          ],
-          [
-            "\"",
-            "“",
-            "”",
-            "«",
-            "»"
-          ],
-          [
-            "'",
-            "‘",
-            "’",
-            "‹",
-            "›"
-          ],
-          [
-            ":"
-          ],
-          [
-            ";"
-          ],
-          [
-            "!",
-            "¡"
-          ],
-          [
-            "?",
-            "¿"
-          ]
-        ],
-        [
-          [
-            "_"
-          ],
-          [
-            "/"
-          ],
-          [
-            " "
-          ],
-          [
-            ","
-          ],
-          [
-            ".",
-            "…"
-          ]
-        ]
-      ]
-    },
-    {
-      "level": "opt+shift",
-      "mode": "locked",
-      "rows": [
-        [
-          [
-            "~"
-          ],
-          [
-            "`"
-          ],
-          [
-            "|"
-          ],
-          [
-            "•",
-            "♪",
-            "♥",
-            "♠",
-            "♦",
-            "♣"
-          ],
-          [
-            "√"
-          ],
-          [
-            "Π",
-            "π"
-          ],
-          [
-            "÷"
-          ],
-          [
-            "×"
-          ],
-          [
-            "¶",
-            "§"
-          ],
-          [
-            "∆"
-          ]
-        ],
-        [
-          [
-            "£"
-          ],
-          [
-            "¥"
-          ],
-          [
-            "$",
-            "¢"
-          ],
-          [
-            "¢"
-          ],
-          [
-            "^",
-            "↑",
-            "↓",
-            "←",
-            "→"
-          ],
-          [
-            "°",
-            "′",
-            "″"
-          ],
-          [
-            "=",
-            "≠",
-            "≈",
-            "∞"
-          ],
-          [
-            "{"
-          ],
-          [
-            "}"
-          ]
-        ],
-        [
-          [
-            "\\"
-          ],
-          [
-            "©"
-          ],
-          [
-            "®"
-          ],
-          [
-            "™"
-          ],
-          [
-            "℅"
-          ],
-          [
-            "["
-          ],
-          [
-            "]"
-          ]
-        ],
-        [
-          [
-            "<",
-            "‹",
-            "≤",
-            "«"
-          ],
-          [
-            ">",
-            "›",
-            "≥",
-            "»"
-          ],
-          [
-            " "
-          ],
-          [
-            ","
-          ],
-          [
-            ".",
-            "…"
-          ]
-        ]
-      ]
-    }
-  ],
-  "locale": "fr",
-  "name": "French"
-}
diff --git a/test/test_cldr2json.py b/test/test_cldr2json.py
deleted file mode 100755 (executable)
index 78a6aa0..0000000
+++ /dev/null
@@ -1,212 +0,0 @@
-#!/usr/bin/python3
-
-import json
-import tempfile
-import unittest
-import xml.etree.ElementTree
-
-import cldr2json
-
-
-class TestParseSingleKey(unittest.TestCase):
-    def test_ascii(self):
-        self.assertEqual(cldr2json.parse_single_key("a"), "a")
-
-    def test_nonascii(self):
-        self.assertEqual(cldr2json.parse_single_key("Æ"), "Æ")
-
-    def test_twochars(self):
-        self.assertEqual(cldr2json.parse_single_key("ԵՒ"), "ԵՒ")
-
-    def test_decode(self):
-        self.assertEqual(cldr2json.parse_single_key("\\u{200D}"), "\u200d")
-
-    def test_decode_threechars(self):
-        self.assertEqual(cldr2json.parse_single_key("ज\\u{94D}ञ"), "ज\u094Dञ")
-
-
-class TestParseRow(unittest.TestCase):
-    def test_parse_row(self):
-        xml_string = """
-        <keyMap>
-            <map iso="D01" to="a" longPress="à â % æ á ä ã å ā ª"/> <!-- Q -->
-            <map iso="D02" to="z"/> <!-- W -->
-            <map iso="D03" to="e" longPress="é è ê ë % ę ė ē"/>
-            <map iso="D04" to="r"/>
-            <map iso="D05" to="t"/>
-            <map iso="D06" to="y" longPress="% ÿ"/>
-            <map iso="D07" to="u" longPress="ù û % ü ú ū"/>
-            <map iso="D08" to="i" longPress="î % ï ì í į ī"/>
-            <map iso="D09" to="o" longPress="ô œ % ö ò ó õ ø ō º"/>
-            <map iso="D10" to="p"/>
-            <map iso="C01" to="q"/> <!-- A -->
-            <map iso="C02" to="s"/>
-            <map iso="C03" to="d"/>
-            <map iso="C04" to="f"/>
-            <map iso="C05" to="g"/>
-            <map iso="C06" to="h"/>
-            <map iso="C07" to="j"/>
-            <map iso="C08" to="k"/>
-            <map iso="C09" to="l"/>
-            <map iso="C10" to="m"/> <!-- ; -->
-            <map iso="B01" to="w"/> <!-- Z -->
-            <map iso="B02" to="x"/>
-            <map iso="B03" to="c" longPress="ç ć č"/>
-            <map iso="B04" to="v"/>
-            <map iso="B05" to="b"/>
-            <map iso="B06" to="n"/>
-            <map iso="B07" to="&apos;" longPress="‘ ’ ‹ ›"/> <!-- M -->
-            <map iso="A02" to=","/> <!-- (key to left of space) -->
-            <map iso="A03" to=" "/> <!-- space -->
-            <map iso="A04" to="." longPress="# ! , ? - : ' @"/> <!-- (key to right of space) -->
-        </keyMap>
-        """
-        xml_tree = xml.etree.ElementTree.XML(xml_string)
-        json = [[
-                 ['a', 'à', 'â', '%', 'æ', 'á', 'ä', 'ã', 'å', 'ā', 'ª'],
-                 ['z'],
-                 ['e', 'é', 'è', 'ê', 'ë', '%', 'ę', 'ė', 'ē'],
-                 ['r'],
-                 ['t'],
-                 ['y', '%', 'ÿ'],
-                 ['u', 'ù', 'û', '%', 'ü', 'ú', 'ū'],
-                 ['i', 'î', '%', 'ï', 'ì', 'í', 'į', 'ī'],
-                 ['o', 'ô', 'œ', '%', 'ö', 'ò', 'ó', 'õ', 'ø', 'ō', 'º'],
-                 ['p']
-                ], [
-                 ['q'],
-                 ['s'],
-                 ['d'],
-                 ['f'],
-                 ['g'],
-                 ['h'],
-                 ['j'],
-                 ['k'],
-                 ['l'],
-                 ['m']
-                ], [
-                 ['w'],
-                 ['x'],
-                 ['c', 'ç', 'ć', 'č'],
-                 ['v'],
-                 ['b'],
-                 ['n'],
-                 ["'", '‘', '’', '‹', '›']
-                ], [
-                 [','],
-                 [' '],
-                 ['.', '#', '!', ',', '?', '-', ':', "'", '@']
-                ]]
-        self.assertEqual(cldr2json.parse_rows(xml_tree), json)
-
-
-class TestConvertXml(unittest.TestCase):
-    def test_convert_xml(self):
-        xml_string = """<?xml version="1.0" encoding="UTF-8" ?>
-        <!DOCTYPE keyboard SYSTEM "../dtd/ldmlKeyboard.dtd">
-        <keyboard locale="fr-t-k0-android">
-            <version platform="4.4" number="$Revision: 11914 $"/>
-            <names>
-                <name value="French"/>
-            </names>
-            <keyMap>
-                <map iso="D01" to="a" longPress="à â % æ á ä ã å ā ª"/> <!-- Q -->
-            </keyMap>
-            <keyMap modifiers="shift caps">
-                <map iso="D01" to="A" longPress="À Â % Æ Á Ä Ã Å Ā ª"/> <!-- Q -->
-            </keyMap>
-            <keyMap modifiers="opt">
-                <map iso="D01" to="1" longPress="¹ ½ ⅓ ¼ ⅛"/> <!-- Q  base=a -->
-            </keyMap>
-            <keyMap modifiers="opt+shift">
-                <map iso="D01" to="~"/> <!-- Q  base=a -->
-            </keyMap>
-        </keyboard>
-        """
-        xml_tree = xml.etree.ElementTree.XML(xml_string)
-        json = {
-          "locale": "fr",
-          "name": "French",
-          "levels": [
-            {
-              "level": "",
-              "mode": "default",
-              "rows": [
-                [
-                  ['a', 'à', 'â', '%', 'æ', 'á', 'ä', 'ã', 'å', 'ā', 'ª'],
-                ]
-              ]
-            },
-            {
-              "level": "shift",
-              "mode": "latched",
-              "rows": [
-                [
-                  ['A', 'À', 'Â', '%', 'Æ', 'Á', 'Ä', 'Ã', 'Å', 'Ā', 'ª'],
-                ]
-              ]
-            },
-            {
-              "level": "opt",
-              "mode": "locked",
-              "rows": [
-                [
-                  ["1", "¹", "½", "⅓", "¼", "⅛"],
-                ]
-              ]
-            },
-            {
-              "level": "opt+shift",
-              "mode": "locked",
-              "rows": [
-                [
-                  ["~"],
-                ]
-              ]
-            }
-          ]
-        }
-        self.assertEqual(cldr2json.convert_xml(xml_tree), json)
-
-
-class TestConvertFile(unittest.TestCase):
-    def test_fr(self):
-        outdir = tempfile.mkdtemp()
-        cldr2json.convert_file("test/data/fr-t-k0-android.xml", outdir)
-        with open("test/data/fr.json", encoding="utf-8") as expected_json_fd:
-            expected_json = json.load(expected_json_fd)
-        with open(outdir + "/fr.json", encoding="utf-8") as actual_json_fd:
-            actual_json = json.load(actual_json_fd)
-        self.assertEqual(expected_json, actual_json)
-
-
-class TestLocaleToXKB(unittest.TestCase):
-    def test_simple(self):
-        self.assertEqual(cldr2json.locale_to_xkb("fr", "French"),
-                         "fr")
-
-    def test_fallback(self):
-        self.assertEqual(cldr2json.locale_to_xkb("nb", "Norwegian Bokmål"),
-                         "no")
-
-    def test_fallback2(self):
-        self.assertEqual(cldr2json.locale_to_xkb("km", "Khmer"),
-                         "kh")
-
-    def test_override(self):
-        self.assertEqual(cldr2json.locale_to_xkb("en-GB",
-                                                 "English Great Britain"),
-                         "uk")
-
-
-class LoadXKBMapplings(unittest.TestCase):
-    def test_dictionnary(self):
-        self.assertIsInstance(cldr2json.load_xkb_mappings(), dict)
-
-    def test_mapping(self):
-        mapping = cldr2json.load_xkb_mappings()
-        self.assertEqual(mapping["French"], "fr")
-
-
-if __name__ == '__main__':
-    unittest.main()